home *** CD-ROM | disk | FTP | other *** search
- /* Link Access Procedures Balanced (LAPB), the upper sublayer of
- * AX.25 Level 2.
- * Copyright 1991 Phil Karn, KA9Q
- *
- * 92/02/07 WG7J
- * Modified to drop ax.25 route records in cases where routes
- * were added by the connections. Inspired by K4TQL
- */
- #include "lapb.h"
- #ifdef AX25
- #include "netrom.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: lapb.c,v 1.17 1997/09/14 14:37:46 root Exp root $";
- #endif
-
- /* This forces data sent by jumpstarting a mailbox connect to
- * resend the header etc. when the first UA reply is missed, and
- * a second SABM is received for the same connection
- * added by Ron Murray VK6ZJM, Murray_RJ@cc.curtin.edu.au
- */
- #define SABM_HOLDOFF
-
- static void handleit (struct ax25_cb * axp, int pid, struct mbuf * bp);
- static void procdata (struct ax25_cb * axp, struct mbuf * bp);
- static int ackours (struct ax25_cb * axp, int16 n);
- static void clr_ex (struct ax25_cb * axp);
- static void enq_resp (struct ax25_cb * axp);
- static void inv_rex (struct ax25_cb * axp);
- static void drop_axr (struct ax25_cb * axp);
-
- /*needed for mailbox jumpstart - WG7J */
- #ifdef MAILBOX
- #ifdef NETROM
- extern struct nrnbr_tab *find_nrnbr (char *, struct iface *);
- #endif
-
- extern int Mbjumpstart;
- extern struct no_js *Exclude;
- #endif
-
-
- /*If we have an AX.25 AUTO route record, drop it.*/
- static void
- drop_axr (struct ax25_cb *axp)
- {
- struct ax_route *axr;
-
- axr = ax_lookup (NULLCHAR, axp->remote, axp->iface, AX_NONSETUP);
- if (axr != NULLAXR && axr->type != AX_LOCAL)
- (void) ax_drop (axp->remote, axp->iface, AX_NONSETUP);
- }
-
-
-
- /* Process incoming frames */
- int
- lapb_input (axp, cmdrsp, bp)
- struct ax25_cb *axp; /* Link control structure */
- int cmdrsp; /* Command/response flag */
- struct mbuf *bp; /* Rest of frame, starting with ctl */
- {
- int control;
- int class; /* General class (I/S/U) of frame */
- int16 type; /* Specific type (I/RR/RNR/etc) of frame */
- char pf; /* extracted poll/final bit */
- char poll = 0;
- char final = 0;
- int16 nr; /* ACK number of incoming frame */
- int16 ns = 0; /* Seq number of incoming frame */
- int16 tmp;
- int recovery = 0;
- #ifdef MAILBOX
- struct no_js *ep; /*scan the 'exclude-calls' list */
- #endif
-
- if (bp == NULLBUF || axp == NULLAX25 || axp->iface == NULLIF) {
- free_p (bp);
- return -1;
- }
- /* Extract the various parts of the control field for easy use */
- if ((control = PULLCHAR (&bp)) == -1) { /*lint !e506 */
- free_p (bp); /* Probably not necessary */
- return -1;
- }
-
- /* update the counters for messages in */
- axp->iface->axcnt.msgin++;
-
- type = ftype (control);
- class = type & 0x3;
- pf = control & PF;
- /* Check for polls and finals */
- if (pf) {
- switch (cmdrsp) {
- case LAPB_COMMAND:
- poll = YES;
- break;
- case LAPB_RESPONSE:
- final = YES;
- break;
- default:
- break;
- }
- }
- /* Extract sequence numbers, if present */
- switch (class) {
- case I:
- case I + 2:
- ns = (control >> 1) & MMASK; /*lint !e702 !e616 */
- case S: /* Note fall-thru */
- default:
- nr = (control >> 5) & MMASK; /*lint !e702 */
- break;
- }
- /* This section follows the SDL diagrams by K3NA fairly closely */
- switch (axp->state) {
- case LAPB_DISCONNECTED:
- switch (type) {
- case SABM: /* Initialize or reset link */
- /* This a new incoming connection. */
- (void) sendctl (axp, LAPB_RESPONSE, UA | pf); /* Always accept */
- clr_ex (axp);
- axp->unack = axp->vr = axp->vs = 0;
- lapbstate (axp, LAPB_CONNECTED); /* Resets state counters */
- axp->srt = axp->iface->ax25->irtt;
- axp->mdev = 0;
- set_timer (&axp->t1, 2 * axp->srt);
- start_timer (&axp->t3);
- start_timer (&axp->t4);
- #ifdef SABM_HOLDOFF
- axp->flags.rxd_I_frame = 0; /* nothing received yet */
- #endif
- /*Jump-start the mailbox. This causes the [NET-H$] prompt to
- *be sent Immediately, instead of after the first data packet
- *Check for connections from known netrom calls,
- *calls from the 'jumpstart exclude' list and check if interface
- *is in vc mode...
- *we don't want to start the mailbox in these cases,
- *since these could be attempts to do level 3 stuff.
- *12/09/91 WG7J
- */
- #ifdef MAILBOX
- if (axp->jumpstarted & IP_LINK)
- break;
- if (Mbjumpstart) {
- #ifdef NETROM
- if (axp->jumpstarted == NETROM_LINK) {
- /* check if the incoming interface is enabled for netrom*/
- if (axp->iface->flags & IS_NR_IFACE)
- if (find_nrnbr (axp->remote, axp->iface) != NULLNTAB)
- /* this is a netrom neighbour*/
- break;
- }
- #endif /* NETROM */
- /*Now check the 'exclude' list*/
- for (ep = Exclude; ep != (struct no_js *) NULL; ep = ep->next)
- if (addreq (axp->remote, ep->call))
- break;
- if (ep != (struct no_js *) NULL) /*exclude this one*/
- break;
-
- /*We passed all tests!*/
- axp->jumpstarted += JUMPSTARTED;
- s_arcall (axp, 0);
- }
- #endif /* MAILBOX */
- break;
- case DISC: /* Always answer a DISC with a DM */
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- break;
- case DM: /* Ignore to avoid infinite loops */
- break;
- default: /* All others get DM */
- if (poll)
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- break;
- }
- if (axp->state == LAPB_DISCONNECTED) { /* we can close connection */
- #if 0
- stop_timer (&axp->t1); /* waste all the timers */
- stop_timer (&axp->t3);
- stop_timer (&axp->t4);
- free_q (&axp->txq); /* lose transmit queue */
- #endif
- drop_axr (axp); /* drop ax25 route */
- del_ax25 (axp); /* clean out the trash */
- free_p (bp);
- return 0;
- }
- break;
- case LAPB_SETUP:
- switch (type) {
- case SABM: /* Simultaneous open */
- (void) sendctl (axp, LAPB_RESPONSE, UA | pf);
- break;
- case DISC:
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- #ifdef NETROM
- nr_derate (axp);
- #endif
- drop_axr (axp); /* drop ax25 route */
- free_q (&axp->txq);
- stop_timer (&axp->t1);
- axp->reason = LB_DM;
- lapbstate (axp, LAPB_DISCONNECTED);
- free_p (bp);
- return 0;
-
- case UA: /* Connection accepted */
- /* Note: xmit queue not cleared */
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- axp->unack = axp->vr = axp->vs = 0;
- lapbstate (axp, LAPB_CONNECTED);
- start_timer (&axp->t4);
- break;
- case DM: /* Connection refused */
- free_q (&axp->txq);
- stop_timer (&axp->t1);
- axp->reason = LB_DM;
- lapbstate (axp, LAPB_DISCONNECTED);
- free_p (bp);
- return 0;
-
- default: /* Respond with DM only to command polls */
- if (poll)
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- break;
- }
- break;
- case LAPB_DISCPENDING:
- switch (type) {
- case SABM:
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- drop_axr (axp); /* drop ax25 route */
- break;
- case DISC:
- (void) sendctl (axp, LAPB_RESPONSE, UA | pf);
- drop_axr (axp); /* drop ax25 route */
- break;
- case UA:
- case DM:
- stop_timer (&axp->t1);
- lapbstate (axp, LAPB_DISCONNECTED);
- free_p (bp);
- return 0;
-
- default: /* Respond with DM only to command polls */
- if (poll)
- (void) sendctl (axp, LAPB_RESPONSE, DM | pf);
- drop_axr (axp); /* drop ax25 route */
- break;
- }
- break;
- case LAPB_RECOVERY: /* folded these two cases together */
- recovery = 1; /* fall through */
- case LAPB_CONNECTED:
- switch (type) {
- case SABM:
- (void) sendctl (axp, LAPB_RESPONSE, UA | pf);
- #ifdef SABM_HOLDOFF
- if (axp->flags.rxd_I_frame) {
- /* only reset if we've had a */
- /* valid I-frame. Otherwise he */
- /* may just not have got our UA */
- #endif
- clr_ex (axp);
- if (!recovery)
- free_q (&axp->txq);
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- axp->unack = axp->vr = axp->vs = 0;
- lapbstate (axp, LAPB_CONNECTED); /* Purge queues */
- if (recovery && !run_timer (&axp->t4))
- start_timer (&axp->t4);
- #ifdef SABM_HOLDOFF
- }
- #endif
- break;
- case DISC:
- free_q (&axp->txq);
- (void) sendctl (axp, LAPB_RESPONSE, UA | pf);
- stop_timer (&axp->t1);
- stop_timer (&axp->t3);
- axp->reason = LB_NORMAL;
- lapbstate (axp, LAPB_DISCONNECTED);
- free_p (bp);
- return 0;
-
- case DM:
- #ifdef NETROM
- if (recovery)
- nr_derate (axp);
- #endif
- axp->reason = LB_DM;
- lapbstate (axp, LAPB_DISCONNECTED);
- free_p (bp);
- return 0;
-
- case UA:
- est_link (axp);
- lapbstate (axp, LAPB_SETUP); /* Re-establish */
- break;
- case FRMR:
- /* update the counters for FRMR in */
- if (axp && axp->iface)
- axp->iface->axcnt.frmerr++;
-
- est_link (axp);
- lapbstate (axp, LAPB_SETUP); /* Re-establish link */
- break;
- case RR:
- case RNR:
- axp->flags.remotebusy = (type == RNR) ? YES : NO;
-
- if (type == RNR)
- /* update the counters for RNR in */
- axp->iface->axcnt.rnrin++;
-
- if (recovery && (axp->proto == V1 || final)) {
- stop_timer (&axp->t1);
- (void) ackours (axp, nr);
- if (axp->unack != 0) {
- if (control != RNR || axp->pthresh != 65535)
- inv_rex (axp);
- else {
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- }
- } else {
- start_timer (&axp->t3);
- lapbstate (axp, LAPB_CONNECTED);
- if (!run_timer (&axp->t4))
- start_timer (&axp->t4);
- }
- } else {
- if (poll)
- enq_resp (axp);
- (void) ackours (axp, nr);
- /* Keep timer running even if all frames
- * were acked, since we must see a Final
- */
- #if 1
- if ((type == RNR) && axp->pthresh == 65535) {
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- } else if (recovery) {
- #endif
- if (!run_timer (&axp->t1))
- start_timer (&axp->t1);
- }
- }
- break;
- case REJ:
- axp->flags.remotebusy = NO;
-
- /* update the counters for rej in */
- axp->iface->axcnt.rejin++;
-
- if (recovery) {
- /* Don't insist on a Final response from the old proto */
- if (axp->proto == V1 || final) {
- stop_timer (&axp->t1);
- (void) ackours (axp, nr);
- if (axp->unack != 0) {
- inv_rex (axp);
- } else {
- start_timer (&axp->t3);
- lapbstate (axp, LAPB_CONNECTED);
- if (!run_timer (&axp->t4))
- start_timer (&axp->t4);
- }
- } else {
- if (poll)
- enq_resp (axp);
- (void) ackours (axp, nr);
- if (axp->unack != 0) {
- /* This is certain to trigger output */
- inv_rex (axp);
- }
- /* A REJ that acks everything but doesn't
- * have the F bit set can cause a deadlock.
- * So make sure the timer is running.
- */
- if (!run_timer (&axp->t1))
- start_timer (&axp->t1);
- }
- } else {
- if (poll)
- enq_resp (axp);
- (void) ackours (axp, nr);
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- /* This may or may not actually invoke transmission,
- * depending on whether this REJ was caused by
- * our losing his prior ACK.
- */
- inv_rex (axp);
- }
- break;
- case I:
- (void) ackours (axp, nr); /** == -1) */
-
- /* update the counters for data in */
- axp->iface->axcnt.datain++;
- #ifdef SABM_HOLDOFF
- axp->flags.rxd_I_frame = 1; /* we got something */
- #endif
- if (recovery) {
- /* Make sure timer is running, since an I frame
- * cannot satisfy a poll
- */
- if (!run_timer (&axp->t1))
- start_timer (&axp->t1);
- } else
- start_timer (&axp->t4);
- if (len_p (axp->rxq) >= axp->window) {
- /* Too bad he didn't listen to us; he'll
- * have to resend the frame later. This
- * drastic action is necessary to avoid
- * deadlock.
- */
- if (recovery || poll) {
- (void) sendctl (axp, LAPB_RESPONSE, RNR | pf);
-
- /* update the counters for rnr out */
- axp->iface->axcnt.rnrout++;
- }
- free_p (bp);
- bp = NULLBUF;
- break;
- }
- /* Reject or ignore I-frames with receive sequence number errors */
- if ((char) ns != axp->vr) {
- if (axp->proto == V1 || !axp->flags.rejsent) {
- axp->flags.rejsent = YES;
- (void) sendctl (axp, LAPB_RESPONSE, REJ | pf);
-
- /* update the counters for rej out */
- axp->iface->axcnt.rejout++;
- } else if (poll)
- enq_resp (axp);
- axp->response = 0;
- break;
- }
- axp->flags.rejsent = NO;
- axp->vr = (axp->vr + 1) & MMASK;
- tmp = len_p (axp->rxq) >= axp->window ? RNR : RR;
- if (poll) {
- (void) sendctl (axp, LAPB_RESPONSE, tmp | PF);
-
- if (tmp == RNR)
- /* update the counters for rnr out */
- axp->iface->axcnt.rnrout++;
- } else
- axp->response = (char) tmp;
-
- procdata (axp, bp);
- bp = NULLBUF;
- break;
- default: /* All others ignored */
- break;
- }
- break;
- default:
- break;
- }
- free_p (bp); /* In case anything's left */
-
- /* See if we can send some data, perhaps piggybacking an ack.
- * If successful, lapb_output will clear axp->response.
- */
- (void) lapb_output (axp);
-
- if (axp && axp->response != 0) {
- (void) sendctl (axp, LAPB_RESPONSE, axp->response);
-
- if (axp->response == RNR)
- /* update the counters for rnr out */
- axp->iface->axcnt.rnrout++;
-
- axp->response = 0;
- }
- return 0;
- }
-
-
-
- /* Handle incoming acknowledgements for frames we've sent.
- * Free frames being acknowledged.
- * Return -1 to cause a frame reject if number is bad, 0 otherwise
- */
- static int
- ackours (struct ax25_cb *axp, int16 n)
- {
- struct mbuf *bp;
- int acked = 0; /* Count of frames acked by this ACK */
- int16 oldest; /* Seq number of oldest unacked I-frame */
- int32 rtt, abserr;
-
- /* Free up acknowledged frames by purging frames from the I-frame
- * transmit queue. Start at the remote end's last reported V(r)
- * and keep going until we reach the new sequence number.
- * If we try to free a null pointer,
- * then we have a frame reject condition.
- */
- oldest = (axp->vs - axp->unack) & MMASK;
- while (axp->unack != 0 && oldest != n) {
- if ((bp = dequeue (&axp->txq)) == NULLBUF) {
- /* Acking unsent frame */
- return -1;
- }
- free_p (bp);
- axp->unack--;
- acked++;
- if (axp->flags.rtt_run && axp->rtt_seq == oldest) {
- /* A frame being timed has been acked */
- axp->flags.rtt_run = 0;
- /* Update only if frame wasn't retransmitted */
- if (!axp->flags.retrans) {
- rtt = msclock () - axp->rtt_time;
- abserr = (rtt > axp->srt) ? rtt - axp->srt :
- axp->srt - rtt;
-
- /* Run SRT and mdev integrators */
- axp->srt = ((axp->srt * 7) + rtt + 4) >> 3; /*lint !e704 */
- axp->mdev = ((axp->mdev * 3) + abserr + 2) >> 2; /*lint !e704 */
- /* Update timeout */
- set_timer (&axp->t1, 4 * axp->mdev + axp->srt);
- }
- }
- axp->flags.retrans = 0;
- axp->retries = 0;
- oldest = (oldest + 1) & MMASK;
- }
- if (axp->unack == 0) {
- /* All frames acked, stop timeout */
- stop_timer (&axp->t1);
- start_timer (&axp->t3);
- } else if (acked != 0) /* Partial ACK; restart timer */
- start_timer (&axp->t1);
-
- if (acked != 0) {
- /* If user has set a transmit upcall, indicate how many frames
- * may be queued
- */
- if (axp->t_upcall != NULLVFP ((struct ax25_cb *, int)))
- (*axp->t_upcall) (axp, axp->paclen * (axp->maxframe - axp->unack));
- }
- return 0;
- }
-
-
-
- /* Establish data link */
- void
- est_link (struct ax25_cb *axp)
- {
- clr_ex (axp);
- axp->retries = 0;
- (void) sendctl (axp, LAPB_COMMAND, SABM | PF);
- stop_timer (&axp->t3);
- start_timer (&axp->t1);
- }
-
-
-
- /* Clear exception conditions */
- static void
- clr_ex (struct ax25_cb *axp)
- {
- axp->flags.remotebusy = NO;
- axp->flags.rejsent = NO;
- axp->response = 0;
- stop_timer (&axp->t3);
- }
-
-
-
- /* Enquiry response */
- static void
- enq_resp (struct ax25_cb *axp)
- {
- char ctl;
-
- ctl = len_p (axp->rxq) >= axp->window ? RNR | PF : RR | PF;
- (void) sendctl (axp, LAPB_RESPONSE, ctl);
-
- if (ctl == (RNR | PF))
- /* update the counters for rnr out */
- axp->iface->axcnt.rnrout++;
-
- axp->response = 0;
- stop_timer (&axp->t3);
- }
-
-
-
- /* Invoke retransmission */
- static void
- inv_rex (struct ax25_cb *axp)
- {
- axp->vs -= axp->unack;
- axp->vs &= MMASK;
- axp->unack = 0;
- }
-
-
-
- /* Send S or U frame to currently connected station */
- int
- sendctl (struct ax25_cb *axp, int cmdrsp, int cmd)
- {
- if ((ftype ((char) cmd) & 0x3) == S) /* Insert V(R) if S frame */
- cmd |= (axp->vr << 5); /*lint !e701 */
-
- return sendframe (axp, cmdrsp, cmd, NULLBUF);
- }
-
-
-
- /* Start data transmission on link, if possible
- * Return number of frames sent
- */
- int
- lapb_output (register struct ax25_cb *axp)
- {
- register struct mbuf *bp;
- struct mbuf *tbp;
- char control;
- int sent = 0;
- int i;
-
- if (axp == NULLAX25 || axp->iface == NULLIF
- || (axp->state != LAPB_RECOVERY && axp->state != LAPB_CONNECTED)
- || axp->flags.remotebusy)
- return 0;
-
- /* Dig into the send queue for the first unsent frame */
- bp = axp->txq;
- for (i = 0; i < axp->unack; i++) {
- if (bp == NULLBUF)
- break; /* Nothing to do */
- bp = bp->anext;
- }
- /* Start at first unsent I-frame, stop when either the
- * number of unacknowledged frames reaches the maxframe limit,
- * or when there are no more frames to send
- */
- while (bp != NULLBUF && axp->unack < axp->maxframe) {
- control = (char) (I | (axp->vs++ << 1) | (axp->vr << 5)); /*lint !e701 */
- axp->vs &= MMASK;
- (void) dup_p (&tbp, bp, 0, len_p (bp));
- if (tbp == NULLBUF)
- return sent; /* Probably out of memory */
- (void) sendframe (axp, LAPB_COMMAND, control, tbp);
- start_timer (&axp->t4);
- axp->unack++;
- /* We're implicitly acking any data he's sent, so stop any
- * delayed ack
- */
- axp->response = 0;
- if (!run_timer (&axp->t1)) {
- stop_timer (&axp->t3);
- start_timer (&axp->t1);
- }
- sent++;
-
- /* update the counters for data out */
- axp->iface->axcnt.dataout++;
-
- bp = bp->anext;
- if (!axp->flags.rtt_run) {
- /* Start round trip timer */
- axp->rtt_seq = (control >> 1) & MMASK; /*lint !e702 */
- axp->rtt_time = msclock ();
- axp->flags.rtt_run = 1;
- }
- }
- return sent;
- }
-
-
-
- /* Set new link state */
- void
- lapbstate (struct ax25_cb *axp, int s)
- {
- int oldstate;
-
- oldstate = axp->state;
- axp->state = s;
- if (s == LAPB_DISCONNECTED) {
- stop_timer (&axp->t1);
- stop_timer (&axp->t3);
- stop_timer (&axp->t4);
- free_q (&axp->txq);
- drop_axr (axp); /* any ax25 route that hasn't been dropped yet*/
- }
- /* Don't bother the client unless the state is really changing */
- if ((oldstate != s) && (axp->s_upcall != NULLVFP ((struct ax25_cb *, int, int))))
- (*axp->s_upcall) (axp, oldstate, s);
- }
-
-
-
- /* Process a valid incoming I frame */
- static void
- procdata (struct ax25_cb *axp, struct mbuf *bp)
- {
- int pid;
- int seq;
-
- /* Extract level 3 PID */
- if ((pid = PULLCHAR (&bp)) == -1) /*lint !e506 */
- return; /* No PID */
-
- if (axp->segremain != 0) {
- /* Reassembly in progress; continue */
- seq = PULLCHAR (&bp); /*lint !e506 */
- if (pid == PID_SEGMENT && (seq & SEG_REM) == axp->segremain - 1) {
- /* Correct, in-order segment */
- append (&axp->rxasm, bp);
-
- /* update the counters for segments in */
- axp->iface->axcnt.segin++;
-
- if ((axp->segremain = (seq & SEG_REM)) == 0) {
-
- /* update the counters for segment errors */
- axp->iface->axcnt.segerr++;
-
- /* Done; kick it upstairs */
- bp = axp->rxasm;
- axp->rxasm = NULLBUF;
- pid = PULLCHAR (&bp); /*lint !e506 */
- handleit (axp, pid, bp);
- }
- } else {
- /* Error! */
- free_p (axp->rxasm);
- axp->rxasm = NULLBUF;
- axp->segremain = 0;
- free_p (bp);
- }
- } else {
- /* No reassembly in progress */
- if (pid == PID_SEGMENT) {
- /* update the counters for segments in */
- axp->iface->axcnt.segin++;
-
- /* Start reassembly */
- seq = PULLCHAR (&bp); /*lint !e506 */
- if (!(seq & SEG_FIRST))
- free_p (bp); /* not first seg - error! */
- else {
- /* Put first segment on list */
- axp->segremain = seq & SEG_REM;
- axp->rxasm = bp;
- }
- } else /* Normal frame; send upstairs */
- handleit (axp, pid, bp);
- }
- }
-
-
-
- /* New-style frame segmenter. Returns queue of segmented fragments, or
- * original packet if small enough
- */
- struct mbuf *
- segmenter (bp, ssize, axp)
- struct mbuf *bp; /* Complete packet */
- int16 ssize; /* Max size of frame segments */
- struct ax25_cb *axp;
- {
- struct mbuf *result = NULLBUF;
- struct mbuf *bptmp, *bp1;
- int16 len, offset;
- int segments;
-
- /* See if packet is too small to segment. Note 1-byte grace factor
- * so the PID will not cause segmentation of a 256-byte IP datagram.
- */
- len = len_p (bp);
- if (len <= ssize + 1)
- return bp; /* Too small to segment */
-
- ssize -= 2; /* ssize now equal to data portion size */
- segments = 1 + (len - 1) / ssize; /* # segments */
- offset = 0;
-
- /* update the counters for seqments out */
- if (axp && axp->iface)
- axp->iface->axcnt.segout += segments;
-
- while (segments != 0) {
- offset += dup_p (&bptmp, bp, offset, ssize);
- if (bptmp == NULLBUF) {
- free_q (&result);
- break;
- }
- /* Make room for segmentation header */
- if ((bp1 = pushdown (bptmp, 2)) == NULLBUF) {
- free_p (bptmp);
- free_q (&result);
- break;
- }
- bp1->data[0] = PID_SEGMENT;
- bp1->data[1] = uchar(--segments);
- if (offset == ssize)
- bp1->data[1] |= SEG_FIRST;
- enqueue (&result, bp1);
- }
- free_p (bp);
- return result;
- }
-
-
-
- static void
- handleit (struct ax25_cb *axp, int pid, struct mbuf *bp)
- {
- struct axlink *ipp;
-
- for (ipp = Axlink; ipp->funct != NULL; ipp++) {
- if (ipp->pid == pid)
- break;
- }
- if (ipp->funct != NULL)
- (*ipp->funct) (axp->iface, axp, NULLCHAR, NULLCHAR, bp, 0);
- else
- free_p (bp);
- }
-
-
-
- #endif /* AX25 */
-